/**
 * 
 */
package com.gmail.avereshchaga.web.controller;

import static com.gmail.avereshchaga.tools.Command.EMPLOYEE_CREATE_COMMAND;
import static com.gmail.avereshchaga.tools.Command.EMPLOYEE_UPDATE_COMMAND;
import static com.gmail.avereshchaga.tools.UrlList.EMPLOYEE_CREATE_URL;
import static com.gmail.avereshchaga.tools.UrlList.EMPLOYEE_LIST_URL;
import static com.gmail.avereshchaga.tools.UrlList.EMPLOYEE_READ_URL;
import static com.gmail.avereshchaga.tools.UrlList.EMPLOYEE_UPDATE_URL;
import static com.gmail.avereshchaga.tools.UrlList.ERROR_URL;
import static com.gmail.avereshchaga.tools.UrlList.LOGIN_URL;
import static com.gmail.avereshchaga.tools.ViewList.EMPLOYEE_CREATE_VIEW;
import static com.gmail.avereshchaga.tools.ViewList.EMPLOYEE_LIST_VIEW;
import static com.gmail.avereshchaga.tools.ViewList.EMPLOYEE_READ_VIEW;
import static com.gmail.avereshchaga.tools.ViewList.EMPLOYEE_UPDATE_VIEW;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import com.gmail.avereshchaga.db.entity.DivisionImpl;
import com.gmail.avereshchaga.db.entity.EmployeeImpl;
import com.gmail.avereshchaga.db.entity.IDivision;
import com.gmail.avereshchaga.db.entity.IEmployee;
import com.gmail.avereshchaga.db.service.IDivisionService;
import com.gmail.avereshchaga.db.service.IEmployeeService;
import com.gmail.avereshchaga.web.form.EmployeeForm;

/**
 * @author <a href="mailto:avereshchaga@gmail.com">Vereshchaga Alexey</a>
 * 
 */
@Controller
public class EmployeeController {

    @Autowired
    private IEmployeeService employeeService;

    @Autowired
    private IDivisionService divisionService;

    private ServiceFunction serviceFunction = new ServiceFunction();

    /**
     * Перенаправляет на страницу EMPLOYEE_LIST_URL
     */
    @RequestMapping(value = "/")
    public String home() {
        return "redirect:/" + EMPLOYEE_LIST_URL;
    }

    /**
     * Выбирает записи сотрудников из БД и
     * выводит их на страницу
     * 
     * @return ModelAndView
     */
    @RequestMapping(value = EMPLOYEE_LIST_URL, method = RequestMethod.GET)
    public ModelAndView findAll() {
        Map<String, Object> model = new HashMap<String, Object>();
        List<IEmployee> employees = new ArrayList();
        employees = employeeService.findAll(serviceFunction.getParam(),
                employeeService.getPage());

        model.put("searchQuery", serviceFunction.getParam());
        model.put("pages", employeeService.getPages());
        model.put("msg", employeeService.getMsg());
        model.put("employees", employees);
        return new ModelAndView(EMPLOYEE_LIST_VIEW, model);
    }

    /**
     * Получает поисковый запрос и страницы
     * 
     * @return ModelAndView
     */
    @RequestMapping(value = EMPLOYEE_LIST_URL, method = RequestMethod.POST)
    public ModelAndView findAll(HttpServletRequest request, HttpSession session) {
        List<IEmployee> employees = new ArrayList();
        serviceFunction.manipulationRequest(request, session);
        String param = (String) session.getAttribute("param");
        String pageStr = request.getParameter("page");
        employees = employeeService.findAll(param, pageStr);

        return new ModelAndView("redirect:/" + EMPLOYEE_LIST_VIEW);
    }

    /**
     * Выводит на страницу форму создания сотрудника
     * 
     * @return ModelAndView
     */
    @RequestMapping(value = EMPLOYEE_CREATE_URL, method = RequestMethod.GET)
    public ModelAndView create() {
        Map<String, Object> model = new HashMap<String, Object>();
        List<IDivision> divisions = divisionService.findAll();
        Collections.sort(divisions, ServiceFunction.SENIORITY_ORDER_DIVISION);
        model.put(EMPLOYEE_CREATE_COMMAND, new EmployeeForm());
        model.put("divisionList", divisions);
        return new ModelAndView(EMPLOYEE_CREATE_VIEW, model);
    }

    /**
     * Сохраняет нового сотрудника
     * 
     * @param employeeForm
     * @param result
     * @throws ParseException
     * @return ModelAndView
     */
    @RequestMapping(value = EMPLOYEE_CREATE_URL, method = RequestMethod.POST)
    public ModelAndView create(
            @Valid @ModelAttribute(EMPLOYEE_CREATE_COMMAND) EmployeeForm employeeForm,
            BindingResult result) throws ParseException {
        if (result.hasErrors()) {
            Map<String, Object> model = new HashMap<String, Object>();
            List<IDivision> divisions = divisionService.findAll();
            Collections.sort(divisions,
                    ServiceFunction.SENIORITY_ORDER_DIVISION);
            model.put(EMPLOYEE_CREATE_COMMAND, new EmployeeForm());
            model.put("divisionList", divisions);
            return new ModelAndView(EMPLOYEE_CREATE_VIEW, model);
        }

        IEmployee employee = new EmployeeImpl();
        IDivision division = new DivisionImpl();

        String firstName = serviceFunction
                .transformationStringForName(employeeForm.getFirstName());
        employee.setFirstName(firstName);

        String lastName = serviceFunction
                .transformationStringForName(employeeForm.getLastName());
        employee.setLastName(lastName);

        employee.setSalary(Double.parseDouble(employeeForm.getSalaryStr()));

        employee.setBirthdate(serviceFunction
                .transformationStringInDateFormat(employeeForm
                        .getBirthdateStr()));

        employee.setActive(true);

        division = divisionService.readDivision(employeeForm.getDivisionId());
        employee.setDivision(division);

        employeeService.createEmployee(employee);
        return new ModelAndView("redirect:../");
    }

    /**
     * Выводит на страницу форму для редактирования сотрудника
     * 
     * @param id
     * @return ModelAndView
     */
    @RequestMapping(value = EMPLOYEE_UPDATE_URL + "/{id}", method = RequestMethod.GET)
    public ModelAndView update(@PathVariable("id") Long id) {
        Map<String, Object> model = new HashMap<String, Object>();
        List<IDivision> divisions = divisionService.findAll();
        Collections.sort(divisions, ServiceFunction.SENIORITY_ORDER_DIVISION);

        EmployeeForm employeeForm = new EmployeeForm();
        IEmployee employee = new EmployeeImpl();
        employee = employeeService.readEmployee(id);

        employeeForm.setId(employee.getId());
        employeeForm.setFirstName(employee.getFirstName());
        employeeForm.setLastName(employee.getLastName());
        employeeForm.setSalaryStr(employee.getSalary().toString());

        employeeForm.setBirthdateStr(serviceFunction
                .transformationDateFormatToString(employee.getBirthdate()));

        employeeForm.setActive(employee.getActive());
        employeeForm.setDivisionId(employee.getDivision().getId());

        model.put(EMPLOYEE_UPDATE_COMMAND, employeeForm);
        model.put("divisionList", divisions);
        model.put("DivisionId", employee.getDivision().getId());
        return new ModelAndView(EMPLOYEE_UPDATE_VIEW, model);
    }

    /**
     * Редактирует сотрудника
     * 
     * @param employeeForm
     * @param result
     * @return ModelAndView
     * @throws ParseException
     */
    @RequestMapping(value = EMPLOYEE_UPDATE_URL + "/{id}", method = RequestMethod.POST)
    public ModelAndView update(
            @Valid @ModelAttribute(EMPLOYEE_UPDATE_COMMAND) EmployeeForm employeeForm,
            BindingResult result) throws ParseException {
        if (result.hasErrors()) {
            Map<String, Object> model = new HashMap<String, Object>();
            List<IDivision> divisions = divisionService.findAll();
            Collections.sort(divisions,
                    ServiceFunction.SENIORITY_ORDER_DIVISION);
            model.put(EMPLOYEE_UPDATE_COMMAND, new EmployeeForm());
            model.put("divisionList", divisions);
            return new ModelAndView(EMPLOYEE_UPDATE_VIEW, model);
        }
        IDivision division = new DivisionImpl();

        EmployeeImpl employee = (EmployeeImpl) employeeService
                .readEmployee(employeeForm.getId());

        employee.setFirstName(employeeForm.getFirstName());
        employee.setLastName(employeeForm.getLastName());

        employee.setSalary(Double.parseDouble(employeeForm.getSalaryStr()));

        employee.setBirthdate(serviceFunction
                .transformationStringInDateFormat(employeeForm
                        .getBirthdateStr()));

        employee.setActive(employeeForm.getActive());

        division = divisionService.readDivision(employeeForm.getDivisionId());
        employee.setDivision(division);

        employeeService.updateEmployee(employee);
        return new ModelAndView("redirect:../../");
    }

    /**
     * Выводит на страницу информацию о сотруднике
     * 
     * @param id
     * @return ModelAndView
     */
    @RequestMapping(value = EMPLOYEE_READ_URL + "/{id}"/*
                                                        * , method =
                                                        * RequestMethod.GET
                                                        */)
    public ModelAndView read(@PathVariable("id") Long id) {
        Map<String, Object> model = new HashMap<String, Object>();
        Long divisionId = employeeService.readEmployee(id).getDivision()
                .getId();
        IEmployee employee = employeeService.readEmployee(id);
        String birthdateStr = serviceFunction
                .transformationDateFormatToString(employee.getBirthdate());
        model.put("birthdateStr", birthdateStr);
        model.put("employee", employee);
        model.put("division", divisionService.readDivision(divisionId));
        return new ModelAndView(EMPLOYEE_READ_VIEW, "model", model);
    }

    /**
     * Выводит на страницу информацию об ошибочном пароле
     */
    @RequestMapping(value = ERROR_URL, method = RequestMethod.GET)
    public String error() {
        return ERROR_URL;
    }

    /**
     * Выводит на страницу форму входа в систему
     */
    @RequestMapping(value = LOGIN_URL, method = RequestMethod.GET)
    public String login() {
        return LOGIN_URL;
    }

    /**
     * @return the employeeService
     */
    public IEmployeeService getEmployeeService() {
        return employeeService;
    }

    /**
     * @param employeeService
     *            the employeeService to set
     */
    public void setEmployeeService(IEmployeeService employeeService) {
        this.employeeService = employeeService;
    }

    /**
     * @return the divisionService
     */
    public IDivisionService getDivisionService() {
        return divisionService;
    }

    /**
     * @param divisionService
     *            the divisionService to set
     */
    public void setDivisionService(IDivisionService divisionService) {
        this.divisionService = divisionService;
    }

    /**
     * @return the serviceFunction
     */
    public ServiceFunction getServiceFunction() {
        return serviceFunction;
    }

    /**
     * @param serviceFunction
     *            the serviceFunction to set
     */
    public void setServiceFunction(ServiceFunction serviceFunction) {
        this.serviceFunction = serviceFunction;
    }
}
